{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 对活动数据进行分析"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 导入工具包"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "#数据量太大，pdandas不能一次讲所有数据读入\n",
    "#也可以用pandas,一次读取部分数据，可以参考：https://www.cnblogs.com/datablog/p/6127000.html\n",
    "#import pandas as pd\n",
    "\n",
    "import numpy as np\n",
    "import scipy.sparse as ss\n",
    "import scipy.io as sio\n",
    "\n",
    "#保存数据\n",
    "import pickle\n",
    "\n",
    "#event的特征需要编码\n",
    "from utils import FeatureEng\n",
    "from sklearn.preprocessing import normalize\n",
    "#相似度/距离\n",
    "import scipy.spatial.distance as ssd\n",
    "from sklearn.preprocessing import normalize\n",
    "from sklearn import metrics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 统计活动数目"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number of records :3137972\n"
     ]
    }
   ],
   "source": [
    "#读取数据，并统计有多少不同的events\n",
    "#其实EDA.ipynb中用read_csv已经统计过了\n",
    "lines = 0\n",
    "fin = open(\"events.csv\", 'rb')\n",
    "#找到用C/C++的感觉了\n",
    "#字段：event_id, user_id,start_time, city, state, zip, country, lat, and lng， 101 columns of words count\n",
    "fin.readline() # skip header，列名行\n",
    "for line in fin:\n",
    "    cols = line.strip().decode('utf8').split(\",\")\n",
    "    lines += 1\n",
    "fin.close()\n",
    "\n",
    "print(\"number of records :%d\" % lines)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里存在py2版本和py3版本的差异，在strip()后面要进行解码.decode('utf8')<br>\n",
    "这里可以看到活动的数目很多，有3137972,居然有300多万<br>\n",
    "这里就用到了之前生成的文件：PE_eventIndex.pkl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number of events in train & test :13418\n"
     ]
    }
   ],
   "source": [
    "#读取训练集和测试集中出现过的活动列表\n",
    "eventIndex = pickle.load(open(\"PE_eventIndex.pkl\", 'rb'))\n",
    "n_events = len(eventIndex)\n",
    "\n",
    "print(\"number of events in train & test :%d\" % n_events)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "读取之前算好的测试集和训练集中出现过的活动，这里又出现了py2和py3的差异，cPickle模块在py3中已经改名pickle，这个问题在之前用户和活动关联关系处理中就出现过，所以这里处理的很快"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 处理events.csv --> 特征编码、活动之间的相似度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "FE = FeatureEng()\n",
    "\n",
    "fin = open(\"events.csv\", 'rb')\n",
    "\n",
    "#字段：event_id, user_id,start_time, city, state, zip, country, lat, and lng， 101 columns of words count\n",
    "fin.readline() # skip header\n",
    "\n",
    "#start_time, city, state, zip, country, lat, and lng\n",
    "eventPropMatrix = ss.dok_matrix((n_events, 7))\n",
    "\n",
    "#词频特征\n",
    "eventContMatrix = ss.dok_matrix((n_events, 101))\n",
    "\n",
    "for line in fin.readlines():\n",
    "    cols = line.strip().decode('utf8').split(\",\")\n",
    "    eventId = str(cols[0])\n",
    "    \n",
    "    if eventId in eventIndex:  #在训练集或测试集中出现\n",
    "        i = eventIndex[eventId]\n",
    "  \n",
    "        #event的特征编码，这里只是简单处理，其实开始时间，地点等信息很重要\n",
    "        eventPropMatrix[i, 0] = FE.getJoinedYearMonth(cols[2]) # start_time\n",
    "        eventPropMatrix[i, 1] = FE.getFeatureHash(cols[3].encode(\"utf-8\")) # city\n",
    "        eventPropMatrix[i, 2] = FE.getFeatureHash(cols[4].encode(\"utf-8\")) # state\n",
    "        eventPropMatrix[i, 3] = FE.getFeatureHash(cols[5].encode(\"utf-8\")) # zip\n",
    "        eventPropMatrix[i, 4] = FE.getFeatureHash(cols[6].encode(\"utf-8\")) # country\n",
    "        eventPropMatrix[i, 5] = FE.getFloatValue(cols[7]) # lat\n",
    "        eventPropMatrix[i, 6] = FE.getFloatValue(cols[8]) # lon\n",
    "        \n",
    "        #词频\n",
    "        for j in range(9, 110):\n",
    "            eventContMatrix[i, j-9] = cols[j]\n",
    "fin.close()\n",
    "\n",
    "#用L2模归一化,Kmeans聚类基于L2距离\n",
    "eventPropMatrix = normalize(eventPropMatrix,\n",
    "    norm=\"l2\", axis=0, copy=False)\n",
    "sio.mmwrite(\"EV_eventPropMatrix\", eventPropMatrix)\n",
    "\n",
    "#词频，可以考虑我们用这部分特征进行聚类，得到活动的genre\n",
    "eventContMatrix = normalize(eventContMatrix,\n",
    "    norm=\"l2\", axis=0, copy=False)\n",
    "sio.mmwrite(\"EV_eventContMatrix\", eventContMatrix)\n",
    "\n",
    "\n",
    "# calculate similarity between event pairs based on the two matrices\n",
    "eventPropSim = ss.dok_matrix((n_events, n_events))\n",
    "eventContSim = ss.dok_matrix((n_events, n_events))\n",
    "\n",
    "#读取在测试集和训练集中出现的活动对\n",
    "uniqueEventPairs = pickle.load(open(\"PE_uniqueEventPairs.pkl\", 'rb'))\n",
    "\n",
    "for e1, e2 in uniqueEventPairs:\n",
    "    #i = eventIndex[e1]\n",
    "    #j = eventIndex[e2]\n",
    "    i = e1\n",
    "    j = e2\n",
    "    \n",
    "    #非词频特征，采用Person相关系数作为相似度\n",
    "    if (i,j) not in eventPropSim:\n",
    "        epsim = ssd.correlation(eventPropMatrix.getrow(i).todense(),\n",
    "            eventPropMatrix.getrow(j).todense())\n",
    "        \n",
    "        eventPropSim[i, j] = epsim\n",
    "        eventPropSim[j, i] = epsim\n",
    "    \n",
    "    #对词频特征，采用余弦相似度，也可以用直方图交/Jacard相似度\n",
    "    if (i,j) not in eventContSim:\n",
    "        ecsim = ssd.cosine(eventContMatrix.getrow(i).todense(),\n",
    "            eventContMatrix.getrow(j).todense())\n",
    "    \n",
    "        eventContSim[i, j] = epsim\n",
    "        eventContSim[j, i] = epsim\n",
    "    \n",
    "sio.mmwrite(\"EV_eventPropSim\", eventPropSim)\n",
    "sio.mmwrite(\"EV_eventContSim\", eventContSim)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里继续记录py2和py3的差异：<br>\n",
    "AttributeError: 'dict' object has no attribute 'has_key'<br>\n",
    "Python 3 已弃用 has_key 这一方法<br>\n",
    "修改前：\n",
    "```\n",
    "if eventIndex.has_key(eventId):  #在训练集或测试集中出现\n",
    "    i = eventIndex[eventId]\n",
    "```\n",
    "修改后：\n",
    "```\n",
    "if eventId in eventIndex:\n",
    "    i = eventIndex[eventId]\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[ 0.,  0.,  0., ...,  0.,  0.,  0.]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eventPropSim.getrow(0).todense()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面就是对活动进行聚类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 对活动进行聚类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#读取数据\n",
    "import scipy.io as sio\n",
    "eventContMatrix = sio.mmread(\"EV_eventContMatrix\") "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from sklearn.cluster import MiniBatchKMeans\n",
    "\n",
    "# 一个参数点（聚类数据为K）的模型，并评价聚类算法性能\n",
    "def K_cluster_analysis(K, df):\n",
    "    print(\"K-means begin with clusters: {}\".format(K));\n",
    "    \n",
    "    #K-means,在训练集上训练\n",
    "    km = MiniBatchKMeans(n_clusters = K)\n",
    "    km.fit(df)\n",
    "    \n",
    "    #保存预测结果\n",
    "    cluster_result = km.predict(df)\n",
    "\n",
    "    # K值的评估标准\n",
    "    #常见的方法有轮廓系数Silhouette Coefficient和Calinski-Harabasz Index\n",
    "    #这两个分数值越大则聚类效果越好\n",
    "    #CH_score = metrics.calinski_harabaz_score(X_train,mb_kmeans.predict(X_train))\n",
    "    CH_score = metrics.silhouette_score(df,cluster_result)   \n",
    "    print(\"CH_score: {}\".format(CH_score))\n",
    "\n",
    "    return CH_score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "K-means begin with clusters: 10\n",
      "CH_score: 0.11778317231213833\n",
      "K-means begin with clusters: 20\n",
      "CH_score: -0.06032136575926976\n",
      "K-means begin with clusters: 30\n",
      "CH_score: -0.0664983444435012\n",
      "K-means begin with clusters: 40\n",
      "CH_score: -0.052651595829654035\n",
      "K-means begin with clusters: 50\n",
      "CH_score: -0.08211569338027233\n",
      "K-means begin with clusters: 60\n",
      "CH_score: -0.09870182978781096\n",
      "K-means begin with clusters: 70\n",
      "CH_score: -0.18219277998755443\n",
      "K-means begin with clusters: 80\n",
      "CH_score: -0.04862792245315227\n",
      "K-means begin with clusters: 90\n",
      "CH_score: -0.14703625480477434\n",
      "K-means begin with clusters: 100\n",
      "CH_score: -0.1968478815965303\n"
     ]
    }
   ],
   "source": [
    "# 设置超参数（聚类数目K）搜索范围\n",
    "CH_scores = []\n",
    "Ks = [10,20,30,40,50,60,70,80,90,100]\n",
    "for K in Ks:\n",
    "    ch = K_cluster_analysis(K, eventContMatrix)\n",
    "    CH_scores.append(ch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.11778317231213833, -0.06032136575926976, -0.066498344443501195, -0.052651595829654035, -0.082115693380272331, -0.09870182978781096, -0.18219277998755443, -0.04862792245315227, -0.14703625480477434, -0.1968478815965303]\n"
     ]
    }
   ],
   "source": [
    "print(CH_scores)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x1a16d1ff60>]"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\nAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a1760e908>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 绘制不同聚类数目的模型的性能，找到最佳模型／参数（分数最高）\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "plt.plot(Ks, np.array(CH_scores), 'b-')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
